package com.wuzheng.wisgo.sanitation.cloud.service.tbox.impl;

import com.alibaba.fastjson.JSONObject;
import com.wuzheng.wisgo.sanitation.cloud.enums.MapTypeEnum;
import com.wuzheng.wisgo.sanitation.cloud.model.tbox.pojo.*;
import com.wuzheng.wisgo.sanitation.cloud.paraandgetutil.HttpClientUtil;
import com.wuzheng.wisgo.sanitation.cloud.paraandgetutil.ParameterRetUtils;
import com.wuzheng.wisgo.sanitation.cloud.repository.entity.gis.MapBase;
import com.wuzheng.wisgo.sanitation.cloud.repository.entity.tbox.ReceiveInfo;
import com.wuzheng.wisgo.sanitation.cloud.enums.JobStatusEnum;
import com.wuzheng.wisgo.sanitation.cloud.repository.mapper.tbox.ReceiveInfoMapper;
import com.wuzheng.wisgo.sanitation.cloud.service.gis.MapBaseService;
import com.wuzheng.wisgo.sanitation.cloud.service.tbox.ReceiveInfoService;
import com.wuzheng.wisgo.sanitation.framework.base.service.impl.BaseServiceImpl;
import com.wuzheng.wisgo.sanitation.framework.util.Assert;
import com.wuzheng.wisgo.sanitation.framework.util.GPSConverterUtils;
import com.wuzheng.wisgo.sanitation.framework.util.StringUtils;
import com.wuzheng.wisgo.sanitation.framework.util.model.GPS;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.net.URL;
import java.net.URLConnection;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;

/**
 * @author：sp
 * @date：Created in 2019-10-10
 * @description：T-Box数据接受表(所有数据)服务实现类
 * @modified By：
 * @version: 1.0
 */
@Service
public class ReceiveInfoServiceImpl extends BaseServiceImpl<ReceiveInfo> implements ReceiveInfoService {

    @Autowired
    private ReceiveInfoMapper receiveInfoMapper;

    @Autowired
    private MapBaseService mapBaseService;


    @Override
    public List<ReceiveInfoToVehicleVo> selectVehCodeToVehicle(ReceiveInfoToVehicleVo receiveInfoToVehicleVo) {
        //在此不需要判断查询的数据集合是否为空，有数据就返回数据list,没有数据就返回空list
        Assert.isTrue(StringUtils.isNotEmpty(receiveInfoToVehicleVo.getCustomerId()), "组织编码不能为空");
        return receiveInfoMapper.selectVehCodeFromVehicle(receiveInfoToVehicleVo.getVehCode(),receiveInfoToVehicleVo.getCustomerId());
    }

    /*
     * @Description: 当前车辆的所有数据
     * @Author: sunpeng
     * @Date: 2019/10/17
     **/
    public ReceiveSelectVehAllDto receiveSelectVehInfo(ReceiveInfoToVehicleVo receiveInfoToVehicleVo) {
        Map<String, Object> map = new HashMap<String, Object>();
        //处理分页前，首先校验数据
        if (receiveInfoToVehicleVo.getSize() <= 0) {
            Assert.isTrue(false, "每页数据条数不能小于等于0");
            logger.error("分页显示的条数小于等于0");
        } else if (receiveInfoToVehicleVo.getCurrent() == null) {
            Assert.isTrue(false, "分页页码不能小于等于0");
            logger.error("分页页码小于等于0");
        }
        //时间格式化
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        map.put("vehCode", receiveInfoToVehicleVo.getVehCode());
        map.put("customerId", receiveInfoToVehicleVo.getCustomerId());
        map.put("size", receiveInfoToVehicleVo.getSize());
        map.put("current", (receiveInfoToVehicleVo.getCurrent() - 1) * receiveInfoToVehicleVo.getSize());
        try {
            map.put("startTime", Timestamp.valueOf(sdf.format(new Date(Long.valueOf(receiveInfoToVehicleVo.getStartTime())))));
            map.put("stopTime", Timestamp.valueOf(sdf.format(new Date(Long.valueOf(receiveInfoToVehicleVo.getStopTime())))));
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("日期转换失败" + e.getMessage());
            Assert.isTrue(false, "日期转换失败" + e.getMessage());
        }
        ReceiveSelectVehAllDto receiveSelectVehAllDto = this.countNumMilesAndTimes(map);
        return receiveSelectVehAllDto;
    }

    /*
     * @Description: 轨迹点
     * @Author: sunpeng
     * @Date: 2019/10/17
     **/
    public ReceiveInfoAllObjectDto selectLongLatAllFromReceice(ReceiveInfoToVehicleVo receiveInfoToVehicleVo) {
        //此对象用于参数的封装
        ReceiveInfoAllObjectDto receiveInfoAllObjectDto = new ReceiveInfoAllObjectDto();
        //时间格式化
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String startTime = null;
        String stopTime = null;
        try {
            startTime = sdf.format(new Date(Long.valueOf(receiveInfoToVehicleVo.getStartTime())));
            stopTime = sdf.format(new Date(Long.valueOf(receiveInfoToVehicleVo.getStopTime())));
        } catch (Exception e) {
            e.printStackTrace();
            Assert.isTrue(false, "轨迹回放查询条件，日期转换失败");
            logger.error("轨迹回放查询条件，日期转换失败！" + e.getMessage());
        }
        //查询所有的轨迹回放点
        List<ReceiveInfoSelectAllDto> longlatInfoLists =
                receiveInfoMapper.selectByLongLatInfo(receiveInfoToVehicleVo.getCustomerId(),
                        MapTypeEnum.GAODE.getTypeId(), receiveInfoToVehicleVo.getVehCode(), Timestamp.valueOf(startTime),
                        Timestamp.valueOf(stopTime));
        if (longlatInfoLists.size() > 0) {
            receiveInfoAllObjectDto.setReceiveInfoList(longlatInfoLists);
        } else {
            receiveInfoAllObjectDto.setReceiveInfoList(new ArrayList<ReceiveInfoSelectAllDto>());
        }
        //查询停留点数据
        List<ReceiveInfoSelectStopTimeDto> stopTimeLists =
                receiveInfoMapper.selectStopLongLatFromStopTime(receiveInfoToVehicleVo.getCustomerId(),
                        MapTypeEnum.GAODE.getTypeId(), receiveInfoToVehicleVo.getVehCode(), Timestamp.valueOf(startTime),
                        Timestamp.valueOf(stopTime));
        if (stopTimeLists.size() > 0) {
            receiveInfoAllObjectDto.setStopTimeLists(stopTimeLists);
        } else {
            receiveInfoAllObjectDto.setStopTimeLists(new ArrayList<ReceiveInfoSelectStopTimeDto>());
        }
        return receiveInfoAllObjectDto;
    }


    /*
     * @Description: 统计总里程，作业里程，运行时间，作业时间，油耗
     * @Author: sunpeng
     * @Date: 2019/10/17
     **/
    public ReceiveSelectVehAllDto countNumMilesAndTimes(Map<String, Object> map) {
        ReceiveSelectVehAllDto receiveSelectVehAllDto = new ReceiveSelectVehAllDto();
        List<ReceiveInfoSelectVehDto> receiveInfoSelectVehDtos = receiveInfoMapper.selectByVehInfo(map);
        Integer total = receiveInfoMapper.selectByCount(map);
        if (total >= 0) {
            receiveSelectVehAllDto.setTotal(total);
        }
        //取得这些主要数据，在存储的的时候就已经做过各种异常处理，现在做的简单异常处理，只是防止意外，理论上可以不用
        if (receiveInfoSelectVehDtos.size() > 0) {
            Double runTotalMiles = 0.0; //运行里程
            Double wokerTotalMiles = 0.0; //作业总里程
            Double notwokerTotalMiles = 0.0; //非作业总里程
            BigDecimal workTotalTime=BigDecimal.ZERO;//运行时间
            BigDecimal notWorkTotalTime=BigDecimal.ZERO; //非作业运行时间
            BigDecimal hourTime = new BigDecimal(1000).multiply(new BigDecimal(60)).multiply(new BigDecimal(60));

            //1.0：计算与运行里程（包括非作业里程）
            //1.01:如果出现异常数据,比如null，不应该影响计算,默认0处理
            Boolean minMilesFlag = Double.isNaN(receiveInfoSelectVehDtos.get(receiveInfoSelectVehDtos.size() - 1).getRecTotalMiles());
            Boolean maxMilesFlag = Double.isNaN(receiveInfoSelectVehDtos.get(0).getRecTotalMiles());
            Double  runMaxMiles= maxMilesFlag ? 0.0 : receiveInfoSelectVehDtos.get(receiveInfoSelectVehDtos.size() - 1).getRecTotalMiles();
            Double  runMinMiles= minMilesFlag ? 0.0 : receiveInfoSelectVehDtos.get(0).getRecTotalMiles();
            //1.02:日志记录异常数据
            if (maxMilesFlag) {
                logger.error("t_receive_info 表中里程数据异常，id" + receiveInfoSelectVehDtos.get(receiveInfoSelectVehDtos.size() - 1).getId());
            } else if (minMilesFlag) {
                logger.error("t_receive_info 表中里程数据异常，id" + receiveInfoSelectVehDtos.get(0).getId());
            }
            //1.03:计算总里程
            runTotalMiles = runMaxMiles - runMinMiles;
            receiveSelectVehAllDto.setRunTotalMiles(runTotalMiles.toString() + "km");

            //2.0:运行时间
            long minRunTime = receiveInfoSelectVehDtos.get(receiveInfoSelectVehDtos.size() - 1).getRecCollectionTime().getTime();
            long maxRunTime = receiveInfoSelectVehDtos.get(0).getRecCollectionTime().getTime();
            long runToTime = maxRunTime - minRunTime;
            String runTotalTime = getTimeHMS(new BigDecimal(runToTime));
            receiveSelectVehAllDto.setRunTotalTime(runTotalTime);

            for (int i = 0; i < receiveInfoSelectVehDtos.size(); i++) {
                //3.0：计算工作里程
                //3.1：先计算空闲中的时间，非作业状态
                if (receiveInfoSelectVehDtos.get(i).getRecJobStatus().equals(JobStatusEnum.STOPPING.getTypeId())) {
                    //非作业里程
                    Double wokerMiles=0D;
                    if(i+1==receiveInfoSelectVehDtos.size()){
                        wokerMiles= receiveInfoSelectVehDtos.get(i).getRecTotalMiles().doubleValue()-receiveInfoSelectVehDtos.get(i-1).getRecTotalMiles().doubleValue();
                    }else {
                        wokerMiles= receiveInfoSelectVehDtos.get(i+1).getRecTotalMiles().doubleValue()-receiveInfoSelectVehDtos.get(i).getRecTotalMiles().doubleValue();
                    }
                    notwokerTotalMiles+=wokerMiles;
                    //4.0 ：非作业时间
                    Long workTime=0L;
                    if(i==0){
                        workTime=receiveInfoSelectVehDtos.get(i).getRecCollectionTime().getTime()-receiveInfoSelectVehDtos.get(i+1).getRecCollectionTime().getTime();
                    }else{
                        workTime=receiveInfoSelectVehDtos.get(i-1).getRecCollectionTime().getTime()-receiveInfoSelectVehDtos.get(i).getRecCollectionTime().getTime();
                    }
                    notWorkTotalTime=new BigDecimal(workTime).add(notWorkTotalTime);
                }

            }
            //3.2:工作里程=运行里程-非作业总里程;
            wokerTotalMiles = runTotalMiles - notwokerTotalMiles;
            receiveSelectVehAllDto.setWorkTotalMiles(wokerTotalMiles.toString() + "km");

            //4.1：作业时间=运行时间-非作业时间
            workTotalTime=new BigDecimal(runToTime).subtract(notWorkTotalTime);
            String workTotalT = getTimeHMS(workTotalTime);
            receiveSelectVehAllDto.setWorkTotalTime(workTotalT);

            //5.0:总油耗
            Boolean minFuelFlag = Double.isNaN(receiveInfoSelectVehDtos.get(receiveInfoSelectVehDtos.size() - 1).getRecFuelQuantity());
            Boolean maxFuelFlag = Double.isNaN(receiveInfoSelectVehDtos.get(0).getRecFuelQuantity());
            Double maxFuel = maxMilesFlag ? 0.0 : receiveInfoSelectVehDtos.get(receiveInfoSelectVehDtos.size() - 1).getRecFuelQuantity();
            Double minFuel= minMilesFlag ? 0.0 : receiveInfoSelectVehDtos.get(0).getRecFuelQuantity();
            //5.1:日志记录异常数据
            if (maxFuelFlag) {
                logger.error("t_receive_info 表中里程数据异常，id" + receiveInfoSelectVehDtos.get(receiveInfoSelectVehDtos.size() - 1).getId());
            } else if (minFuelFlag) {
                logger.error("t_receive_info 表中里程数据异常，id" + receiveInfoSelectVehDtos.get(0).getId());
            }
            double fuelTotal = maxFuel - minFuel;
            receiveSelectVehAllDto.setVehicleItemLists(receiveInfoSelectVehDtos);
            receiveSelectVehAllDto.setFuelTotal(Double.toString(fuelTotal)+"L");
        }
        return receiveSelectVehAllDto;
    }

    /*
     * @MethodName: getTimeHMS
     * @Description: 时间格式转换D天H小时M分钟S秒
     * @Param: [time]
     * @Return: java.lang.String
     * @Author: sunpeng
     * @Date: 2019/11/13
    **/
    private String getTimeHMS(BigDecimal time){
        //毫秒转换秒
        BigDecimal secondTime = time.divide(new BigDecimal(1000),BigDecimal.ROUND_HALF_UP);
        BigDecimal minuteTime=BigDecimal.ZERO; //分
        BigDecimal hourTime=BigDecimal.ZERO; //小时
        BigDecimal dayTime=BigDecimal.ZERO; //天
        if(secondTime.compareTo(new BigDecimal(60))>0){ //如果秒数大于60，将秒数转换成整数
            //返回数组中包含两个元素，第一个元素为两数相除的商，第二个元素为余数
            BigDecimal[] timeArray = secondTime.divideAndRemainder(new BigDecimal(60));
            minuteTime=timeArray[0];
            secondTime=timeArray[1];
            //如果分钟大于60，将分钟转换成小时
            if(minuteTime.compareTo(new BigDecimal(60))>0){
                BigDecimal[] dmArray = minuteTime .divideAndRemainder(new BigDecimal(60));
                hourTime=dmArray[0];
                minuteTime=dmArray[1];
                //如果小时大于12，就转换成天
                if(hourTime.compareTo(new BigDecimal(24))>0){
                    BigDecimal[] dArray = hourTime .divideAndRemainder(new BigDecimal(24));
                    dayTime=dArray[0];
                    hourTime=dArray[1];
                }
            }
        }
        String result="";
        if(minuteTime.compareTo(BigDecimal.ZERO)>0){
            result=""+minuteTime+"min"+result;
        } if(hourTime.compareTo(BigDecimal.ZERO)>0){
            result=" "+hourTime+"h"+result;
        } if(dayTime.compareTo(BigDecimal.ZERO)>0){
            result=" "+dayTime+"天"+result;
        }
        return result;
    }



    @Override
     public void getAddressByPoint(String vehId,String mapType) throws Exception {
        String url_getAdByPoint= ParameterRetUtils.getPropertiesParameter("gaode.url");
        String amap_key=ParameterRetUtils.getPropertiesParameter("gaode.key");
        long start = System.currentTimeMillis();
        List<ReceiveInfo> receiveInfos = receiveInfoMapper.selectByVehId(vehId);
        logger.info("数据查询时间："+(System.currentTimeMillis()-start)+"   总数据量："+receiveInfos.size());
        if(receiveInfos.size()>0){
                for(ReceiveInfo receiveInfo:receiveInfos){
                    MapBase mapBase=new MapBase();
                    Double lat=receiveInfo.getRecLatitude();
                    Double log=receiveInfo.getRecLongitude();
                    //再转换数据之前先查询数据是否存在，后期如果使用缓存，应该下面查询缓存中是否存在这个数据，如果不存在再去数据库查询
                    int countMape = mapBaseService.selectLonLat(lat, log,mapType);
                    if(countMape!=0){
                        //说明数据已经转换过了，不用再次转换
                        continue;
                    }
                    //如果没有，则转换并插入数据库，并同步更新缓存redis
                    mapBase= mapBaseService.getAddressByPoint(url_getAdByPoint,amap_key,lat,log,MapTypeEnum.GAODE.getTypeId());
                    mapBaseService.insert(mapBase);
                }
        }
        logger.info("数据转换完成时间："+(System.currentTimeMillis()-start));
    }
}
